/*
 * Copyright 2014-2016 wjokhttp
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.mainaer.wjoklib.okhttp.upload;

import android.database.sqlite.SQLiteDatabase;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import lombok.Data;
import lombok.experimental.Accessors;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * 上传线程
 *
 * @author hst
 * @date 2016/9/6 .
 */
@Data
@Accessors(chain = true)
public class UploadTask implements Runnable {

    static String BOUNDARY = "----------" + System.currentTimeMillis();
    public static final MediaType MEDIA_TYPE_BOUNDARY = MediaType.parse("multipart/form-data;boundary=" + BOUNDARY);
    private OkHttpClient mClient;
    private SQLiteDatabase db;
    private UploadTaskListener mListener;
    private String id;// task id
    private String uploadUrl;// file url
    private String fileName; //保存文件名
    private String filePath; //文件储存路径
    private int uploadStatus;
    private int chunk, chunks;//流块
    private Handler mHandler;

    @Override
    public void run() {
        mClient = new OkHttpClient();
        initHandler();

        try {
            int blockLength = 1024 * 1024;
            File file = new File(filePath);
            chunks = (int) Math.ceil((double) file.length() / blockLength);
            while (chunk <= chunks && uploadStatus != UploadStatus.UPLOAD_STATUS_PAUSE && uploadStatus != UploadStatus.UPLOAD_STATUS_ERROR) {
                onCallBack(UploadStatus.UPLOAD_STATUS_UPLOADING, "");
                Map<String, String> params = new HashMap<>();
                params.put("filename", fileName);
                params.put("chunks", chunks + "");
                params.put("chunk", chunk + "");
                byte[] mBlock = FileUtils.getBlock(file, (chunk - 1) * blockLength, blockLength);
                MultipartBody.Builder builder = new MultipartBody.Builder()
                        .setType(MultipartBody.FORM);
                addFromDataParams(builder, params);

                RequestBody requestBody = RequestBody.create(MEDIA_TYPE_BOUNDARY, mBlock);
                builder.addFormDataPart("file", fileName, requestBody);
                Request request = new Request.Builder()
                        .url(uploadUrl)
                        .post(builder.build())
                        .build();
                Response response = mClient.newCall(request).execute();
                if (!response.isSuccessful()) {
                    uploadStatus = UploadStatus.UPLOAD_STATUS_ERROR;
                    onCallBack(UploadStatus.UPLOAD_STATUS_ERROR, response.message());
                } else {
                    onCallBack(UploadStatus.UPLOAD_STATUS_UPLOADING, "");
                    chunk++;
                }
            }
            if (chunk >= chunks) {
                uploadStatus = UploadStatus.UPLOAD_STATUS_COMPLETED;
                onCallBack(UploadStatus.UPLOAD_STATUS_COMPLETED, "");
            }
        } catch (IOException e) {
            uploadStatus = UploadStatus.UPLOAD_STATUS_ERROR;
            onCallBack(UploadStatus.UPLOAD_STATUS_ERROR, e.getLocalizedMessage());
            e.printStackTrace();
        }
    }

    private void initHandler() {
        mHandler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                int code = msg.what;
                switch (code) {
                    // 上传失败
                    case UploadStatus.UPLOAD_STATUS_ERROR:
                        mListener.onError(UploadTask.this, code, (String) msg.obj);
                        break;
                    // 正在上传
                    case UploadStatus.UPLOAD_STATUS_UPLOADING:
                        mListener.onUploading(UploadTask.this, chunk, chunks);
                        break;
                    // 上传完成
                    case UploadStatus.UPLOAD_STATUS_COMPLETED:
                        mListener.onUploadSuccess(UploadTask.this, fileName);
                        break;
                    // 暂停上传
                    case UploadStatus.UPLOAD_STATUS_PAUSE:
                        mListener.onPause(UploadTask.this);
                        break;
                }
            }
        };
    }

    /**
     * 分发回调事件到ui层
     */
    private void onCallBack(int uploadStatus, String msg) {
        Message.obtain(mHandler, uploadStatus, msg).sendToTarget();
    }

    private void addFromDataParams(MultipartBody.Builder builder, Map<String, String> params) {
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + key + "\""),
                        RequestBody.create(null, params.get(key)));
            }
        }
    }

}
